﻿
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using HandyControl.Controls;
using HardToolApp.Model;
using HardToolApp.Tool;
using HardToolApp.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace HardToolApp.ViewModel
{
    [ViewModelHelper("GPIO", typeof(GpioPage), typeof(GpioModel), typeof(GpioModel.GPIO), Sort = 2)]
    internal class GpioVM: PeripheralVM
    {
        public RelayCommand<GpioModel.GPIO> ModeSetCmd { get; set; }
        public RelayCommand<GpioModel.GPIO> SetReadCmd { get; set; }
        public RelayCommand<GpioModel.GPIO> MoreCmd { get; set; }

        void ModeSetCommand(GpioModel.GPIO t)
        {
            t.subCmd = (byte)GpioModel.GPIOType.MODE_SET;
            Send(t);
        }

        void SetReadCommand(GpioModel.GPIO t)
        {
            if(t.Mode == GPIOMode.Output || t.Mode == GPIOMode.OutputOD)
            {
                t.subCmd = (byte)GpioModel.GPIOType.SET_LEVEL;
            }
            else
            {
                t.subCmd = (byte)GpioModel.GPIOType.READ_LEVEL;
            }

            Send(t);
        }

        void MoreCommand(GpioModel.GPIO t)
        {
            t.subCmd = (byte)GpioModel.GPIOType.HL_CHANGE;
            Send(t);
        }
        public GpioVM() {
            ModeSetCmd = new RelayCommand<GpioModel.GPIO> (ModeSetCommand);
            SetReadCmd = new RelayCommand<GpioModel.GPIO>(SetReadCommand);
            MoreCmd = new RelayCommand<GpioModel.GPIO> (MoreCommand);
            ScriptVM.register("gpio_mode_set","(引脚id,模式)", "GPIO",this.GetType(),"引脚输入输出模式设置，0：输入 1：上拉输入 2：下拉输入 3：输出 4:开漏输出", "0:操作成功,1:引脚设置失败");
            ScriptVM.register("gpio_hl_change", "(引脚id,起始电平，第一段时间，第二段时间，重复次数)", "GPIO", this.GetType(), "高低电平转化", "0:操作成功,1:引脚设置失败");
            ScriptVM.register("gpio_set", "(引脚id,高低电平)", "GPIO", this.GetType(), "设置高低电平", "0:操作成功,1:引脚设置失败");
            ScriptVM.register("gpio_read", "(引脚id)", "GPIO", this.GetType(), "引脚电平读取", "0:操作成功,1:引脚读取失败");
        }
        static string[] ResString = { "操作成功", "引脚设置失败","高低电平切换设置失败", "电平设置失败" , "电平读取失败" , "引脚编号超出最大引脚号" };
        static string[] PinMap = { "PB4", "PB5", "PB10", "PB11" };

        public override void Rec(object t,byte[] b)
        {
            if (b[5] != 0)
            {
                USBInfoVM.USBVm.AddMap((b[3] << 8) + b[4], b[5]);
                Growl.Warning(ResString[b[5]]);
            }
            else
            {
                if (b[4] == (byte)CommSubGPIO.COMM_SUB_GPIO_LEVEL_READ)
                {
                    if (b[6] >= 4)
                    {
                        USBInfoVM.USBVm.AddMap((b[3] << 8) + b[4], 5);
                        Growl.Warning(ResString[5]);
                    }
                    else
                    {
                        ((GpioModel)Model).GPIOs[b[6]].Level = b[7] > 0?true:false;
                        USBInfoVM.USBVm.AddMap((b[3] << 8) + b[4], b[7]);
                    }
                }
                else
                {
                    USBInfoVM.USBVm.AddMap((b[3] << 8) + b[4], 0);
                }
            }
        }

        #region GPIO
        public static object gpio_mode_set(byte id,byte mode)
        {
            byte[] bytes = new byte[8];
            bytes[0] = 0x55;
            bytes[1] = 0xaa;
            bytes[2] = (byte)bytes.Length;
            bytes[3] = (byte)CommCmd.COMM_GPIO;
            bytes[4] = (byte)CommSubGPIO.COMM_SUB_GPIO_PIN_SET;
            bytes[5] = (byte)id;
            bytes[6] = (byte)mode;
            bytes[7] = Common.chksum(bytes);
            return USBInfoVM.USBVm.send(bytes);
        }

        public static object gpio_hl_change(byte id,byte start,UInt16 first,UInt16 second,UInt16 repeat)
        {
            byte[] bytes = new byte[14];
            bytes[0] = 0x55;
            bytes[1] = 0xaa;
            bytes[2] = (byte)bytes.Length;
            bytes[3] = (byte)CommCmd.COMM_GPIO;
            bytes[4] = (byte)CommSubGPIO.COMM_SUB_GPIO_HL_CHANGE;
            bytes[5] = id;
            bytes[6] = (byte)(start);
            bytes[7] = (byte)(first >> 8);
            bytes[8] = (byte)(first & 0xff);
            bytes[9] = (byte)(second >> 8);
            bytes[10] = (byte)(second & 0xff);
            bytes[11] = (byte)(repeat >> 8);
            bytes[12] = (byte)(repeat & 0xff);
            bytes[13] = Common.chksum(bytes);
            return USBInfoVM.USBVm.send(bytes);
        }

        public static object gpio_set(byte id,byte level)
        {
            byte[] bytes = new byte[8];
            bytes[0] = 0x55;
            bytes[1] = 0xaa;
            bytes[2] = (byte)bytes.Length;
            bytes[3] = (byte)CommCmd.COMM_GPIO;
            bytes[4] = (byte)CommSubGPIO.COMM_SUB_GPIO_LEVEL_SET;
            bytes[5] = id;
            bytes[6] = (byte)(level);
            bytes[7] = Common.chksum(bytes);
            return USBInfoVM.USBVm.send(bytes);
        }

        public static object gpio_read(byte id)
        {
            byte[] bytes = new byte[7];
            bytes[0] = 0x55;
            bytes[1] = 0xaa;
            bytes[2] = (byte)bytes.Length;
            bytes[3] = (byte)CommCmd.COMM_GPIO;
            bytes[4] = (byte)CommSubGPIO.COMM_SUB_GPIO_LEVEL_READ;
            bytes[5] = id;
            bytes[6] = Common.chksum(bytes);
            return USBInfoVM.USBVm.send(bytes);
        }

        public override void Send(Peripheral peripheral)
        {
            GpioModel.GPIO m = (GpioModel.GPIO)peripheral;
            if (m.subCmd == (byte)GpioModel.GPIOType.MODE_SET)
            {
                gpio_mode_set(m.ID,(byte)m.Mode);
            }
            else if (m.subCmd == (byte)GpioModel.GPIOType.HL_CHANGE)
            {
                gpio_hl_change(m.ID,(byte)(m.StartLevel==true?1:0),m.FirstHoldTime,m.SecondHoldTime,m.RepeatTimes);
            }
            else if (m.subCmd == (byte)GpioModel.GPIOType.SET_LEVEL)
            {
                gpio_set(m.ID,(byte)(m.Level == true ? 1 : 0));
            }
            else if (m.subCmd == (byte)GpioModel.GPIOType.READ_LEVEL)
            {
                gpio_read(m.ID);
            }
        }
        #endregion

    }
}
